package com.mdd.admin.service.order.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.query.MPJQueryWrapper;
import com.mdd.admin.LikeAdminThreadLocal;
import com.mdd.admin.service.order.IOrderService;
import com.mdd.admin.validate.common.PageParam;
import com.mdd.admin.validate.order.OrderParam;
import com.mdd.admin.vo.order.OrderListVo;
import com.mdd.admin.vo.order.OrderDetailVo;
import com.mdd.admin.vo.order.OrderLogListVo;
import com.mdd.common.core.PageResult;
import com.mdd.common.entity.course.Course;
import com.mdd.common.entity.order.Order;
import com.mdd.common.entity.order.OrderLog;
import com.mdd.common.enums.OrderEnum;
import com.mdd.common.enums.OrderLogEnum;
import com.mdd.common.mapper.order.OrderLogMapper;
import com.mdd.common.mapper.order.OrderMapper;
import com.mdd.common.mapper.order.OrderRefundMapper;
import com.mdd.common.utils.*;
import com.mdd.common.config.GlobalConfig;
import org.aspectj.weaver.ast.Or;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * 订单实现类
 * @author panweiliang
 */
@Service
public class OrderServiceImpl implements IOrderService {

    @Resource
    OrderMapper orderMapper;

    @Resource
    OrderLogMapper orderLogMapper;

    /**
     * 订单列表
     *
     * @author panweiliang
     * @param pageParam 分页参数
     * @param params 搜索参数
     * @return PageResult<OrderListVo>
     */
    @Override
    public PageResult<OrderListVo> list(PageParam pageParam, Map<String, String> params) {
        Integer page  = pageParam.getPageNo();
        Integer limit = pageParam.getPageSize();
        MPJQueryWrapper<Order> mpjQueryWrapper = new MPJQueryWrapper<Order>()
                .selectAll(Order.class)
                .select("user.nickname as nickname, user.id as userId, user.sn as userSn, user.avatar AS avatar, oc.course_snap as courseSnap, course.name as courseName, course.cover as courseCover, course.sell_price as courseSellPrice, teacher.name AS teacherName ")
                .innerJoin("?_user user ON user.id=t.user_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_order_course oc ON oc.order_id=t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_course course ON course.id=oc.course_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .leftJoin("?_teacher teacher ON course.teacher_id = teacher.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .isNull("t.delete_time")
                .orderByDesc(Arrays.asList("t.id"));

        if (StringUtil.isNotEmpty(params.get("keyword"))) {
            String keyword = params.get("keyword");
            mpjQueryWrapper.nested(wq->wq
                    .like("user.sn", keyword).or()
                    .like("user.nickname", keyword).or()
                    .like("user.mobile", keyword));
        }

        String orderStatus = params.get("orderStatus");
        if (StringUtil.isNotEmpty(orderStatus) && !"0".equals(orderStatus)) {
            mpjQueryWrapper.eq("t.order_status", orderStatus);
        }

        orderMapper.setSearch(mpjQueryWrapper, params, new String[]{
                "like:sn@t.sn:str",
                "datetime:startTime-endTime@t.create_time:str",
                "=:payStatus@t.pay_status:int",
                "=:refundStatus@t.refund_status:int",
                "like:teacherName@teacher.name:str",
                "like:courseName@course.name:str",
        });
        IPage<OrderListVo> iPage = orderMapper.selectJoinPage(new Page<>(page, limit), OrderListVo.class, mpjQueryWrapper);
        for(OrderListVo item : iPage.getRecords()) {
            item.setAvatar(UrlUtil.toAbsoluteUrl(item.getAvatar()));
            item.setCreateTime(TimeUtil.timestampToDate(item.getCreateTime()));
            item.setUpdateTime(TimeUtil.timestampToDate(item.getUpdateTime()));
            item.setCancelTime(TimeUtil.timestampToDate(item.getCancelTime()));
            item.setPayTime(TimeUtil.timestampToDate(item.getPayTime()));
            item.setRefundTime(TimeUtil.timestampToDate(item.getRefundTime()));
            item.setCourseCover(UrlUtil.toAbsoluteUrl(item.getCourseCover()));
        }
        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), iPage.getRecords());
    }


    /**
     * 订单列表
     *
     * @author panweiliang
     */
    @Override
    public Map<String, Object> count() {

        Map<String, Object> count = new HashMap<>();
        count.put("all_num", orderMapper.countAll());
        count.put("waitpay_num", orderMapper.countByOrderStatus(1));
        count.put("complete_num", orderMapper.countByOrderStatus(2));
        count.put("close_num", orderMapper.countByOrderStatus(3));
        return count;

    }




    @Override
    public List<OrderLogListVo> listLog(Integer orderId) {
        MPJQueryWrapper<OrderLog> mpjQueryWrapper = new MPJQueryWrapper<OrderLog>()
                .selectAll(OrderLog.class)
                .select("user.nickname as operatorNickname, user.avatar AS operatorAvatar ")
                .innerJoin("?_user user ON user.id=t.operator_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .eq("t.order_id", orderId)
                .orderByDesc(Arrays.asList("t.id"));

        List<OrderLogListVo> orderLogListVos = orderLogMapper.selectJoinList(OrderLogListVo.class, mpjQueryWrapper);
        for(OrderLogListVo item : orderLogListVos) {
            item.setOperatorAvatar(UrlUtil.toAbsoluteUrl(item.getOperatorAvatar()));
            item.setCreateTime(TimeUtil.timestampToDate(item.getCreateTime()));
            item.setUpdateTime(TimeUtil.timestampToDate(item.getUpdateTime()));
        }
        return orderLogListVos;
    }

    /**
     * 订单详情
     *
     * @author panweiliang
     * @param id 主键参数
     * @return Order
     */
    @Override
    public OrderDetailVo detail(Integer id) {
        MPJQueryWrapper<Order> mpjQueryWrapper = new MPJQueryWrapper<Order>()
                .selectAll(Order.class)
                .select("user.sn as userSn, user.nickname as nickname, user.id as userId, user.avatar AS avatar, oc.course_snap as courseSnap, course.name as courseName, course.cover as courseCover, course.sell_price as courseSellPrice ")
                .innerJoin("?_user user ON user.id=t.user_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_order_course oc ON oc.order_id=t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_course course ON course.id=oc.course_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .eq("t.id", id)
                .last("limit 1")
                .orderByDesc(Arrays.asList("t.id"));

        OrderDetailVo vo = orderMapper.selectJoinOne(OrderDetailVo.class, mpjQueryWrapper);
        Assert.notNull(vo, "数据不存在");
        vo.setAvatar(UrlUtil.toAbsoluteUrl(vo.getAvatar()));
        vo.setCreateTime(TimeUtil.timestampToDate(vo.getCreateTime()));
        vo.setCancelTime(TimeUtil.timestampToDate(vo.getCancelTime()));
        vo.setPayTime(TimeUtil.timestampToDate(vo.getPayTime()));
        vo.setRefundTime(TimeUtil.timestampToDate(vo.getRefundTime()));
        vo.setCourseCover(UrlUtil.toAbsoluteUrl(vo.getCourseCover()));
        return vo;
    }

    /**
     * 订单新增
     *
     * @author panweiliang
     * @param orderParam 参数
     */
    @Override
    public void add(OrderParam orderParam) {
        Order model = new Order();
        model.setSn(orderParam.getSn());
        model.setTransactionId(orderParam.getTransactionId());
        model.setUserId(orderParam.getUserId());
        model.setOrderTerminal(orderParam.getOrderTerminal());
        model.setOrderStatus(orderParam.getOrderStatus());
        model.setPayStatus(orderParam.getPayStatus());
        model.setPayWay(orderParam.getPayWay());
        model.setPayTime(orderParam.getPayTime());
        model.setTotalAmount(orderParam.getTotalAmount());
        model.setOrderAmount(orderParam.getOrderAmount());
        model.setRefundStatus(orderParam.getRefundStatus());
        model.setCancelTime(orderParam.getCancelTime());
        model.setRefundTime(orderParam.getRefundTime());
        model.setShopRemark(orderParam.getShopRemark());
        model.setCreateTime(System.currentTimeMillis() / 1000);
        model.setUpdateTime(System.currentTimeMillis() / 1000);
        orderMapper.insert(model);
    }

    /**
     * 订单编辑
     *
     * @author panweiliang
     * @param orderParam 参数
     */
    @Override
    public void edit(OrderParam orderParam) {
        Order model = orderMapper.selectOne(
                new QueryWrapper<Order>()
                    .eq("id",  orderParam.getId())
                    .last("limit 1"));

        Assert.notNull(model, "数据不存在!");

        model.setId(orderParam.getId());
        model.setSn(orderParam.getSn());
        model.setTransactionId(orderParam.getTransactionId());
        model.setUserId(orderParam.getUserId());
        model.setOrderTerminal(orderParam.getOrderTerminal());
        model.setOrderStatus(orderParam.getOrderStatus());
        model.setPayStatus(orderParam.getPayStatus());
        model.setPayWay(orderParam.getPayWay());
        model.setPayTime(orderParam.getPayTime());
        model.setTotalAmount(orderParam.getTotalAmount());
        model.setOrderAmount(orderParam.getOrderAmount());
        model.setRefundStatus(orderParam.getRefundStatus());
        model.setCancelTime(orderParam.getCancelTime());
        model.setRefundTime(orderParam.getRefundTime());
        model.setShopRemark(orderParam.getShopRemark());
        model.setUpdateTime(System.currentTimeMillis() / 1000);
        orderMapper.updateById(model);
    }

    /**
     * 订单删除
     *
     * @author panweiliang
     * @param id 主键ID
     */
    @Override
    public void del(Integer id) {
        Order model = orderMapper.selectOne(
                new QueryWrapper<Order>()
                    .eq("id", id)
                    .last("limit 1"));

        Assert.notNull(model, "数据不存在!");
        Assert.isTrue(model.getOrderStatus().intValue() == OrderEnum.ORDER_STATUS_CLOSED.getCode(), "订单未关闭状态，无法删除");
        model.setDeleteTime(TimeUtil.timestamp());
        this.orderMapper.updateById(model);
    }

    /**
     * 取消订单
     *
     * @author panweiliang
     * @param id 主键ID
     */
    @Override
    public void cancel(Integer id) {
        Integer adminId = LikeAdminThreadLocal.getAdminId();
        Order model = orderMapper.selectOne(
                new QueryWrapper<Order>()
                        .eq("id", id)
                        .last("limit 1"));

        Assert.notNull(model, "订单数据不存在!");
        Assert.isTrue(model.getOrderStatus().intValue() == OrderEnum.ORDER_STATUS_UNPAID.getCode(), "订单非待付款状态，无法取消");
        model.setCancelTime(TimeUtil.timestamp());
        model.setOrderStatus(OrderEnum.ORDER_STATUS_CLOSED.getCode());
        this.orderMapper.updateById(model);

        OrderLog orderLog = new OrderLog();
        orderLog.setOrderId(model.getId());
        orderLog.setContent(OrderLogEnum.CHANNEL_SYSTEM_CANCEL_ORDER.getMsg());
        orderLog.setChannel(OrderLogEnum.CHANNEL_SYSTEM_CANCEL_ORDER.getCode());
        orderLog.setOperatorId(adminId);
        orderLog.setType(OrderLogEnum.TYPE_SYSTEM.getCode());
        orderLog.setUpdateTime(TimeUtil.timestamp());
        orderLog.setCreateTime(TimeUtil.timestamp());
        orderLogMapper.insert(orderLog);
    }

    @Override
    public Order changeShopRemark(OrderParam orderParam) {
        Order model = orderMapper.selectOne(
                new QueryWrapper<Order>()
                        .eq("id",  orderParam.getId())
                        .last("limit 1"));
        Assert.notNull(model, "数据不存在!");
        model.setShopRemark(orderParam.getShopRemark());
        model.setUpdateTime(System.currentTimeMillis() / 1000);
        orderMapper.updateById(model);
        return model;
    }

    @Override
    public Map<String, Object> getOrderStatistic() {
        Map<String, Object> statistic = new LinkedHashMap<>();
        statistic.put("salesAmount", this.orderMapper.getSalesAmount());
        statistic.put("salesOrderCount", this.orderMapper.getSalesOrderCount());
        return statistic;
    }

    @Override
    public Long getSalesOrderCount(Long start, Long end) {
        return this.orderMapper.getSalesOrderCountByTimestamp(start, end);
    }

    @Override
    public BigDecimal getSalesAmount(Long start, Long end) {
        return this.orderMapper.getSalesAmountByTimestamp(start, end);
    }

    @Override
    public List<Map<String, BigDecimal>> getSalesAmountFromPast7days() {

        try {
            return this.orderMapper.getSalesAmountFromPast7days();
        } catch (Exception e) {

        }

        return null;
    }

    @Override
    public void closeOvertimeOrders() {
        String cancelUnpaidOrders = LsConfigUtil.get("transaction", "cancel_unpaid_orders");
        String cancelUnpaidOrdersTimesStr = LsConfigUtil.get("transaction", "cancel_unpaid_orders_times", "30");
        if ("1".equals(cancelUnpaidOrders) && cancelUnpaidOrdersTimesStr != null && !"null".equals(cancelUnpaidOrdersTimesStr)) {
            Long cancelUnpaidOrdersTimes = Long.parseLong(cancelUnpaidOrdersTimesStr);
            List<Order> orders = this.orderMapper.getOvertimeOrders(cancelUnpaidOrdersTimes * 60);
            orders.forEach(item -> {
                item.setOrderStatus(OrderEnum.ORDER_STATUS_CLOSED.getCode());
                item.setCancelTime(TimeUtil.timestamp());
                int result = this.orderMapper.updateById(item);
                if (result > 0) {
                    OrderLog orderLog = new OrderLog();
                    orderLog.setContent(OrderLogEnum.CHANNEL_SYSTEM_CANCEL_ORDER.getMsg());
                    orderLog.setOrderId(item.getId());
                    orderLog.setType(OrderLogEnum.TYPE_SYSTEM.getCode());
                    orderLog.setChannel(OrderLogEnum.CHANNEL_SYSTEM_CANCEL_ORDER.getCode());
                    orderLog.setOperatorId(0);
                    orderLog.setCreateTime(TimeUtil.timestamp());
                    orderLog.setUpdateTime(TimeUtil.timestamp());
                    this.orderLogMapper.insert(orderLog);
                }
            });
        }

    }
}
